﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;
using StackExchange.Redis;

namespace Redis
{
    class RedisDemo
    {
        //键值对
        public static void StringTest()
        {
            // Using：定义了一个范围，等范围结束以后进行资源的释放，结束后调用Dispose()
            using (ConnectionMultiplexer conn = RedisHelper.RedisConn)
            {
                //测试0，文件夹下入数据
                string key0 = "StringTest:";

                //默认为db0
                //括号内可填写1-15，如var db2 = conn.GetDatabase(2);
                var db = conn.GetDatabase(); //在Redis中获得与数据库的交互式连接

                db.StringSet(key0 + "num", "138");
                db.StringSet(key0 + "time", DateTime.Now.ToString());
                var num = db.StringGet("StringTest:num");
                Console.WriteLine(num);

                //测试1，写入数据，读取数据
                string key = "StringTest";
                if (db.KeyExists(key))
                    db.KeyDelete(key);

                db.StringSet(key, "1008611");
                var value = db.StringGet(key);
                string sd = value.ToString();
                Console.WriteLine(value);

                //测试2，获取当前时间
                string key2 = "StringTest2";

                //如果key已经存在并且是字符串，则此命令将值附加在字符串的末尾
                //如果key不存在，则会创建它并将其设置为空字符串，类似于SET
                //if (db.KeyExists(key2))
                //     db.KeyDelete(key2);
                //db.StringAppend(key2, DateTime.Now.ToString());

                db.StringSet(key2, DateTime.Now.ToString());
                Console.WriteLine(db.StringGet(key2));

                //测试3，控制台写入
                string value3 = Console.ReadLine();
                Console.WriteLine("value3=" + value3);
                string key3 = "StringTest3";
                db.StringSet(key3, value3);
                Console.WriteLine(db.StringGet(key3));

                // 测试4，批量读写数据
                // KeyValuePair<RedisKey, RedisValue>[] values
                //以KeyValuePair数组形式批量写入
                var keyvp1 = new KeyValuePair<RedisKey, RedisValue>("name1", "Jhon");
                var keyvp2 = new KeyValuePair<RedisKey, RedisValue>("name2", "Lilei");
                var keyvp3 = new KeyValuePair<RedisKey, RedisValue>("name3", "Jim");
                KeyValuePair<RedisKey, RedisValue>[] values = { keyvp1, keyvp2, keyvp3 };
                db.StringSet(values);

                //批量读取key的值
                RedisKey[] rkarray = { "name1", "name2", "name3" };
                RedisValue[] rvarray = db.StringGet(rkarray);
                foreach (var item in rvarray)
                {
                    Console.WriteLine(item);
                }

                //测试5，将对象以Json格式存入string中
                db.StringSet("myfirstname", "Li");
                string str = db.StringGet("myfirstname");
                db.StringSet("mylastname", "Shuxian", TimeSpan.FromSeconds(20));//设置时间，20s后过期。
                str = db.StringGet("mylastname");

                //创建对象
                UserInfoDto User1 = new UserInfoDto()
                {
                    Id = 97,
                    LastLoginTime = DateTime.Now,
                    Password = "xxxxxx",
                    StaffId = "xxxxxx",
                    StaffName = "xxx"
                };

                string user1_Json = JsonConvert.SerializeObject(User1);//序列化，对象转化为Json格式
                db.StringSet("stringtest_Json", user1_Json);

                string user1_JsonResult = db.StringGet("stringtest_Json");//读取Json格式的key
                Console.WriteLine(user1_JsonResult);

                User1 = JsonConvert.DeserializeObject<UserInfoDto>(user1_JsonResult);//反序列化
                Console.WriteLine(User1);
            }
        }

        //Hash类型
        //string类型的域和值的映射表
        //常用来存储对象信息
        public static void HashTest()
        {
            // C# 泛型集合 List<数据类型>
            List<UserInfoDto> list = new List<UserInfoDto>();
            for (int i = 0; i < 11; ++i)
            {
                list.Add(new UserInfoDto()
                {
                    Id = i,
                    LastLoginTime = DateTime.Now,
                    Password = "password_" + i.ToString(),
                    StaffId = "StaffId_" + i.ToString(),
                    StaffName = "StaffName_" + i.ToString()
                });
            }

            using (ConnectionMultiplexer conn = RedisHelper.RedisConn)
            {
                //测试1：对象序列化为JSON字符串写入
                string key = "HashSetTest";
                var db = conn.GetDatabase();
                if (db.KeyExists(key))
                    db.KeyDelete(key);

                //string listKey = IdentityMap.CreateKey<UserInfoDto>();
                HashEntry[] items = new HashEntry[list.Count];

                for (int i = 1; i < list.Count; i++)
                {
                    // 将指定的对象序列化为JSON字符串。
                    string json = JsonConvert.SerializeObject(list[i]);
                    db.HashSet(key, list[i].Id, json);

                    Console.WriteLine(db.HashGet(key, list[i].Id));
                    Console.WriteLine(db.HashGet(key, "StaffId"));

                    db.HashDelete(key, "password");//无效
                }

                //测试2：将对象以plain text格式希尔
                string key2 = "HashSetTest2";
                //if (db.KeyExists(key2))
                //    db.KeyDelete(key2);
                //为哈希表的每一个域设值
                //bool HashSet(RedisKey key, RedisValue hashField, RedisValue value)
                for (int i = 1; i < 5; i++)
                {
                    key2 = "HashSetTest" + list[i].Id.ToString();
                    if (db.KeyExists(key2))
                        db.KeyDelete(key2);

                    db.HashSet(key2, "ID", list[i].Id);
                    db.HashSet(key2, "password", list[i].Password);
                    db.HashSet(key2, "StaffId", list[i].StaffId);
                    db.HashSet(key2, "StaffName", list[i].StaffName);
                    db.HashSet(key2, "LastLoginTime", DateTime.Now.ToString());

                    Console.WriteLine(db.HashGet(key2, list[i].Id));
                    //删除key中的域
                    db.HashDelete(key2, "password");
                }

                //测试3：删除key中的域
                string key3 = "HashDeletTest";
                db.HashSet(key3, "ID", 123456111111111111);
                db.HashSet(key3, "password", "xxxxxx");
                db.HashSet(key3, "StaffId", "xxxxxxxxxx");
                db.HashDelete(key3, "password");

            }
            Console.ReadLine();
        }

        //列表数据类型
        //列表按照插入顺序排序，可将一个元素插入列表的头部和尾部
        public static void ListTest()
        {
            using (ConnectionMultiplexer conn = RedisHelper.RedisConn)
            {
                string key = "ListTest";
                var db = conn.GetDatabase();
                if (db.KeyExists(key))
                    db.KeyDelete(key);

                for (int i = 0; i < 10; i++)
                {
                    // 将指定的值插入存储在key的列表的开头 ，相当于栈
                    // 如果键不存在，则在执行推入操作之前将其创建为空列表
                    db.ListLeftPush(key, "left_" + i.ToString());
                    db.ListRightPush(key, "right_" + i.ToString());
                }
                Console.WriteLine("写入完成");
                var length = db.ListLength(key); //读出list的长度
                Console.WriteLine(length);

                var str = db.ListLeftPop(key); //从顶部拿出数据
                Console.WriteLine(str);
                str = db.ListRightPop(key); //从底部拿出数据
                Console.WriteLine(str);

                //返回存储在键列表中指定的元素。
                //偏移量start和stop是从零开始的索引，0是列表的第一个元素（列表的头），1是下一个元素，依此类推。
                //这些偏移也可以是负数，表示从列表。用于示例，-1是列表的最后一个元素，-2是倒数第二个元素，依此类推。
                //注意，如果您有一个从0到100的数字列表，LRANGE list 0 10将返回11个元素，也就是说，包含最右边的项。
                var list = db.ListRange(key, 0, 4);
                foreach (var item in list)
                {
                    Console.WriteLine(item);
                }

                str = db.ListRemove(key, "left_2"); //删除list中的单个数值
                Console.WriteLine(str);

                str = db.ListInsertAfter(key, list[3], "After"); //在某一位置后插入数据
                Console.WriteLine(str);
                str = db.ListInsertBefore(key, list[3], "Before"); //在某一位置前插入数据
                Console.WriteLine(str);

                //删除list中的数据
                //while (db.ListLength(key) != 0)
                //{
                //    //从redis数据库弹出List里的数据
                //    var strTest = db.ListRightPop(key);
                //    Console.WriteLine(str);
                //}
            }
        }

        //Set是String类型的无序集合
        public static void SetTest()
        {
            List<UserInfoDto> list = new List<UserInfoDto>();
            DateTime dt = DateTime.Now;
            for (int i = 1; i < 4; i++)
            {
                list.Add(new UserInfoDto()
                {
                    Id = i,
                    LastLoginTime = dt,
                    Password = "password" + i.ToString(),
                    StaffId = "StaffId_" + i.ToString(),
                    StaffName = "StaffName_" + i.ToString()
                });
            }

            using (ConnectionMultiplexer conn = RedisHelper.RedisConn)
            {
                //测试1
                string key = "SetTest:";
                var db = conn.GetDatabase();
                db.KeyDelete(key);
                db.KeyDelete("HashSetTest");
                //string listKey = IdentityMap.CreateKey<UserInfoDto>();
                HashEntry[] items = new HashEntry[list.Count];
                for (int i = 0; i < list.Count; i++)
                {
                    string json = JsonConvert.SerializeObject(list[i]);
                    db.KeyDelete(key + list[i].Id.ToString());

                    // 以Json格式存储
                    db.SetAdd(key + list[i].Id.ToString(), json);

                    //以string格式存储

                    db.SetAdd(key + list[i].Id.ToString() + ":Id", list[i].Id);
                    db.SetAdd(key + list[i].Id.ToString() + ":password", list[i].Password);
                    db.SetAdd(key + list[i].Id.ToString() + ":StaffId", list[i].StaffId);
                    db.SetAdd(key + list[i].Id.ToString() + ":StaffName", list[i].StaffName);
                    db.SetAdd(key + list[i].Id.ToString() + ":LastLoginTime", DateTime.Now.ToString());

                    //SSCAN命令用于对集合进行增量迭代。
                    //注意：要通过游标恢复迭代，请将原始的可枚举或枚举数转换为IScanningCursor。
                    var result = db.SetScan(key, "*password99*");
                    Console.WriteLine(result);
                }
                Console.WriteLine("Complete test1!");


                //测试2，set命令
                //冒号后可在目录下创建文件夹
                string key2 = "citys:";
                db.KeyDelete(key2);
                RedisValue[] citys1 = { "北京", "上海", "广州" };
                db.SetAdd(key2 + "1", citys1);
                RedisValue[] citys2 = { "成都", "重庆", "西安" };
                db.SetAdd(key2 + "2", citys2);
                RedisValue[] citys3 = { "太原", "大连", "徐州" };
                db.SetAdd(key2 + "3", citys3);
                db.SetMove("citys:2", "citys:1", "成都");
                db.SetRemove("citys:3", "大连");
            }
        }

        //有序集合
        //每个集合元素都有一个对应的double类型的分数
        public static void SortedSet()
        {
            List<UserInfoDto> list = new List<UserInfoDto>();
            for (int i = 1; i < 5; i++)
            {
                list.Add(new UserInfoDto()
                {
                    Id = i,
                    LastLoginTime = DateTime.Now,
                    Password = "password" + i.ToString(),
                    StaffId = "StaffId_" + i.ToString(),
                    StaffName = "StaffName_" + i.ToString()
                });
            }

            using (ConnectionMultiplexer conn = RedisHelper.RedisConn)
            {
                //测试2
                var db = conn.GetDatabase();
                string key = "SortedSetTest:";
                db.KeyDelete("SortedSetTest");

                foreach (var item in list)
                {
                    string json = JsonConvert.SerializeObject(item);
                    db.KeyDelete(key + item.Id.ToString());
                    db.KeyDelete("SortedSetTest" + item.Id.ToString() + ":name");
                    db.KeyDelete("SortedSetTest" + item.Id.ToString() + ":StaffId");
                    //db.SetAdd(key + item.Id.ToString(), json);
                    db.SortedSetAdd(key + item.Id.ToString() + ":name", item.StaffName, item.Id);
                    db.SortedSetAdd(key + item.Id.ToString() + ":StaffId", item.StaffName, item.Id);
                }

                Console.WriteLine("写入完成");
                Console.WriteLine("读取两条记录");

                var result = db.SortedSetRangeByRank(key, 1, 3);
                for (int i = 0; i < result.Length; i++)
                {
                    Console.WriteLine(result[i]);
                }

                var result2 = db.SortedSetRangeByRankWithScores(key, 0, -1, Order.Descending);

                var result3 = db.SortedSetScan(key, "*99*", 10).ToList();
                for (int i = 0; i < result3.Count; i++)
                {
                    Console.WriteLine(result3[i]);
                }
                Console.ReadLine();

                //测试1
                string key0 = "SortedSetTest0";
                var db2 = conn.GetDatabase(2);
                var rep = db2.SortedSetAdd(key0, "北京", 6521);
                Console.WriteLine(rep);

                var city1 = new SortedSetEntry("北京", 4451);
                var city2 = new SortedSetEntry("上海", 3400);
                var city3 = new SortedSetEntry("广州", 3459);

                var city4 = new SortedSetEntry("成都", 3300);
                var city5 = new SortedSetEntry("太原", 2459);
                SortedSetEntry[] citys = { city1, city2, city3, city4, city5 };
                var rep2 = db2.SortedSetAdd(key0, citys);
                Console.WriteLine(rep2);

                var res = db2.SortedSetRangeByRank(key0, 1, 3);
                for (int i = 0; i < res.Length; i++)
                {
                    Console.WriteLine(res[i]);
                }


            }
        }

        /// <summary>
        /// 订阅
        /// </summary>
        public static void Subscribe(string channelName)
        {
            ConnectionMultiplexer conn = RedisHelper.RedisConn;

            var sub = conn.GetSubscriber();
            sub.Subscribe(channelName, SubHandel);
            Console.WriteLine("订阅了一个频道：" + channelName);

        }

        private static void SubHandel(RedisChannel cnl, RedisValue val)
        {
            Console.WriteLine();
            Console.WriteLine("频道：" + cnl + "\t收到消息:" + val); ;
            Console.WriteLine("线程：" + Thread.CurrentThread.ManagedThreadId + ",是否线程池：" + Thread.CurrentThread.IsThreadPoolThread);

            ConnectionMultiplexer conn = RedisHelper.RedisConn;

            if (val == "close")
                conn.GetSubscriber().Unsubscribe(cnl);
            if (val == "closeall")
                conn.GetSubscriber().UnsubscribeAll();


        }

        public static void PublishMsg(string channelName, string msg)
        {
            ConnectionMultiplexer conn = RedisHelper.RedisConn;

            var publisher = conn.GetSubscriber();

            publisher.Publish("msg", "message_content");

        }
    }

}
